package com.lb.uts.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lb.uts.constants.UTSConstants;
import com.lb.uts.entity.ScheduleJob;
import com.lb.uts.mapper.ScheduleJobMapper;
import com.lb.uts.entity.JobSearch;
import com.lb.uts.exception.UTSException;
import com.lb.uts.service.AbstractBaseService;
import com.lb.uts.service.IScheduleJobService;
import com.lb.uts.service.manager.SchedulerManager;
import com.lb.uts.util.IdUtils;
import com.lb.uts.util.PolicyUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author liangb
 * @version 3.0
 * @date 2019/4/26 17:23
 */
@Service
public class ScheduleJobService extends AbstractBaseService<ScheduleJobMapper, ScheduleJob> implements IScheduleJobService {

    @Autowired
    private ScheduleJobMapper scheduleJobMapper;

    @Autowired
    private SchedulerManager schedulerManager;


    /**
     * 查询未被删除的定时任务
     *
     * @return 未删除的定时任务列表
     */
    public List<ScheduleJob> selectUnDeleteList() {
        return scheduleJobMapper.queryUnDeleteList();
    }

    /**
     * 根据jobName进行查询
     *
     * @param jobName 任务名
     */
    public int selectUniqe(String jobName, String jobGroup) {
        return scheduleJobMapper.selectUniqe(jobName, jobGroup);
    }

    /**
     * 根据jobName和jobGroup查询唯一的任务
     *
     * @param jobName
     * @param jobGroup
     * @return 定时任务或者NULL
     */
    public ScheduleJob selectUniqeJob(String jobName, String jobGroup) {
        return scheduleJobMapper.selectUniqeJob(jobName, jobGroup);
    }

    public int updateRedRunNum(String jobId, String possession, Integer concurrentNum) {
        return scheduleJobMapper.updateRunNum(jobId, possession, concurrentNum, -1);
    }

    /**
     * 不做数量限制的时候，做累加操作
     *
     * @param jobId
     * @param concurrentNum 并行数量
     * @param num
     * @return 操作数目
     */
    public int updateRunNum(String jobId, String possession, Integer concurrentNum, int num) {
        int result = scheduleJobMapper.updateRunNumNoCondition(jobId, possession, concurrentNum, num);
        //并发情况下可能possession结果不对
        ScheduleJob scheduleJob = getById(jobId);
        if (scheduleJob.getRunNum() == 0 && StringUtils.isNotBlank(scheduleJob.getPossession())) {
            result = updatePossession(jobId);
        }
        return result;
    }

    public int updateIncRunNum(String jobId, String possession, Integer concurrentNum) {
        return scheduleJobMapper.updateRunNum(jobId, possession, concurrentNum, 1);
    }


    public int updateStatus(ScheduleJob scheduleJob) {
        scheduleJob.setJobStatus(UTSConstants.JOB_STATUS_DELETE);
        return scheduleJobMapper.updateById(scheduleJob);
    }

    public PageInfo<ScheduleJob> queryList(JobSearch jobSearch, int pageNo, int pageSize) {
        PageHelper.startPage(pageNo, pageSize);
        List<ScheduleJob> scheduleJobList = scheduleJobMapper.queryByJobSearch(jobSearch);
        PageInfo<ScheduleJob> page = new PageInfo<>(scheduleJobList);
        return page;
    }

    /**
     * 立即执行
     *
     * @param jobId
     */
    public void executeJob(String jobId) throws Exception {
        ScheduleJob job = this.getById(jobId);
        schedulerManager.triggerJob(job);
    }

    @Override
    @Transactional
    public Integer saveJobInfo(ScheduleJob scheduleJob, Integer concurrentCount) throws SchedulerException {
        String jobId = IdUtils.nextUUID();
        scheduleJob.setJobId(jobId);
        if (scheduleJob.getConcurrentNum() == null) {
            scheduleJob.setConcurrentNum(0);
        } else if (scheduleJob.getConcurrentNum() == 1) {
            scheduleJob.setConcurrentNum(concurrentCount);
        }
        scheduleJob.setVersion(0L);
        scheduleJob.setRunNum(0);
        scheduleJob.setCreateTime(LocalDateTime.now());
        int num = scheduleJobMapper.insert(scheduleJob);
        if (num <= 0) {
            return num;
        }
        //新建任务
        PolicyUtil.SCHEDULE_JOB_LIST.add(scheduleJob);
        addJob(jobId);
        //  updateJob(jobId);
        return num;
    }

    /**
     * 添加任务
     *
     * @param jobId
     */
    @Transactional
    public void addJob(String jobId) throws SchedulerException {
        ScheduleJob job = this.getById(jobId);
        schedulerManager.addJob(job);
    }

    /**
     * 修改任务
     *
     * @param jobId
     * @return
     * @auth njq
     */
    @Transactional
    public void updateJob(String jobId) throws SchedulerException {
        ScheduleJob job = this.getById(jobId);
        schedulerManager.updateJob(job);

    }

    /**
     * 暂停任务
     *
     * @param jobId
     * @return
     * @author liuml
     */
    @Transactional
    public void pauseJob(String jobId) throws SchedulerException {
        ScheduleJob job = this.getById(jobId);
        if (job != null) {
            job.setJobStatus(UTSConstants.JOB_STATUS_PAUSE);
            job.setVersion(job.getVersion() + 1);
            int rs = this.updateScheduleJob(job);
            if (rs > 0) {
                schedulerManager.pauseJob(job);
            } else {
                throw new SchedulerException("更新任务状态失败");
            }
        } else {
            throw new SchedulerException("该任务不存在");
        }
    }


    /**
     * 恢复任务
     *
     * @param jobId
     */
    @Transactional
    public void resumeJob(String jobId) throws SchedulerException {
        ScheduleJob job = this.getById(jobId);
        if (job != null) {
            job.setJobStatus(UTSConstants.JOB_STATUS_NORMAL);
            job.setVersion(job.getVersion() + 1);
            int rs = this.updateScheduleJob(job);
            if (rs > 0) {
                schedulerManager.resumeJob(job);
            } else {
                throw new SchedulerException("更新任务状态失败");
            }
        } else {
            throw new SchedulerException("该任务不存在");
        }
    }


    /**
     * 删除任务
     *
     * @param jobId
     */
    @Transactional
    public void deleteJob(String jobId) throws SchedulerException {
        ScheduleJob job = this.getById(jobId);
        if (job != null) {
            job.setJobStatus(UTSConstants.JOB_STATUS_DELETE);
            job.setVersion(job.getVersion() + 1);
            int rs = this.updateScheduleJob(job);
            if (rs > 0) {
                schedulerManager.deleteJob(job);
            } else {
                throw new SchedulerException("更新任务状态失败");
            }
        } else {
            throw new SchedulerException("该任务不存在");
        }
    }


    /**
     * 修改任务
     */
    @Transactional
    public void updateJob(ScheduleJob scheduleJob, Integer concurrentCount) throws UTSException, SchedulerException {

        //获取数据库中任务信息
        ScheduleJob scheduleJobDb = scheduleJobMapper.selectById(scheduleJob.getJobId());
        Integer concurrentCountNumDb = scheduleJobDb.getConcurrentNum();
        if (scheduleJob.getConcurrentNum() != concurrentCountNumDb) {
            //当两次结果不一致的时候
            if (concurrentCountNumDb != concurrentCount && scheduleJobDb.getRunNum() > 0) {
                throw new UTSException("", "有正在运行的任务，无法变更执行策略");
            }
        }
        if (!scheduleJob.getDepend().equals(scheduleJobDb.getDepend())) {
            if (scheduleJobDb.getRunNum() > 0) {
                throw new UTSException("", "有正在运行的任务，无法变更执行策略");
            }
        }
        //修改任务
        if (scheduleJob.getConcurrentNum() == 1) {
            scheduleJob.setConcurrentNum(concurrentCount);
        }
        scheduleJob.setVersion(scheduleJob.getVersion() + 1);
        int num = scheduleJobMapper.updateById(scheduleJob);
        if (num <= 0) {
            throw new UTSException("", "修改任务失败");
        }
    }

    /**
     * 修改任务
     */
    public int updateScheduleJob(ScheduleJob scheduleJob) {
        return scheduleJobMapper.updateById(scheduleJob);
    }

    @Override
    public int updatePossession(String jobId) {
        return scheduleJobMapper.updatePossessionById(jobId);
    }
}
